import { Request, BodyType } from '../../models/request.model';
import { MessageService } from '../../services/message.service';
import { formatDate } from '../../utils/utils';

// 请求类型枚举
export enum RequestType {
    ALL = 'all',
    FETCH_XHR = 'fetch-xhr',
    CSS = 'css',
    JS = 'js',
    IMG = 'img',
    OTHER = 'other'
}

/**
 * 请求列表管理类
 * 负责管理网站请求列表
 */
export class RequestsManager {
    // 网站请求记录元素
    private siteUrl: HTMLHeadingElement;
    private refreshRequestsButton: HTMLButtonElement;
    private filterRequestsInput: HTMLInputElement;
    private filterMethodSelect: HTMLSelectElement;
    private filterTypeSelect: HTMLSelectElement;
    private clearRequestsButton: HTMLButtonElement;
    private requestsList: HTMLDivElement;
    private requestsEmptyState: HTMLDivElement;

    // 网站请求数据
    private tabRequests: Request[] = [];
    private filteredRequests: Request[] = [];

    // 回调函数
    private onRequestSelect: (request: Request) => void;

    /**
     * 构造函数
     * @param onRequestSelect 选择请求的回调函数
     */
    constructor(onRequestSelect: (request: Request) => void) {
        this.onRequestSelect = onRequestSelect;

        // 获取DOM元素
        this.siteUrl = document.getElementById('site-url') as HTMLHeadingElement;
        this.refreshRequestsButton = document.getElementById('refresh-requests') as HTMLButtonElement;
        this.filterRequestsInput = document.getElementById('filter-requests') as HTMLInputElement;
        this.filterMethodSelect = document.getElementById('filter-method') as HTMLSelectElement;
        this.filterTypeSelect = document.getElementById('filter-type') as HTMLSelectElement;
        this.clearRequestsButton = document.getElementById('clear-requests') as HTMLButtonElement;
        this.requestsList = document.getElementById('requests-list') as HTMLDivElement;
        this.requestsEmptyState = document.querySelector('.requests-empty-state') as HTMLDivElement;

        // 初始化复制按钮
        const copyButton = document.getElementById('copy-url') as HTMLButtonElement;
        if (copyButton) {
            copyButton.addEventListener('click', this.handleCopyUrl.bind(this));
        }

        // 初始化
        this.setupEventListeners();
        this.loadTabRequests();
    }

    /**
     * 设置事件监听器
     */
    private setupEventListeners(): void {
        // 刷新请求按钮
        this.refreshRequestsButton.addEventListener('click', () => this.loadTabRequests());

        // 筛选请求输入框
        this.filterRequestsInput.addEventListener('input', () => this.filterRequests());

        // 筛选方法下拉框
        this.filterMethodSelect.addEventListener('change', () => this.filterRequests());

        // 筛选类型下拉框
        this.filterTypeSelect.addEventListener('change', () => this.filterRequests());

        // 清空请求按钮
        this.clearRequestsButton.addEventListener('click', () => {
            this.tabRequests = [];
            this.filteredRequests = [];
            this.updateRequestsList();
        });
    }

    /**
     * 加载标签页的请求
     */
    public async loadTabRequests(): Promise<void> {
        try {
            // 显示加载状态
            this.requestsList.innerHTML = '';
            this.requestsEmptyState.style.display = 'block';
            this.requestsEmptyState.textContent = '正在加载请求...';

            // 发送消息获取所有请求
            const result = await MessageService.getTabRequests();

            if (result && result.success) {
                // 更新网站URL
                if (result.tabUrl) {
                    const fullUrl = result.tabUrl;
                    
                    // 设置URL为按钮的data属性，避免展示时发生HTML转义
                    const copyButton = document.getElementById('copy-url') as HTMLButtonElement;
                    if (copyButton) {
                        copyButton.dataset.url = fullUrl;
                    }
                    
                    // 设置URL文本，使用textContent避免HTML转义问题
                    this.siteUrl.textContent = decodeURIComponent(fullUrl);
                } else {
                    this.siteUrl.textContent = '未知';
                    const copyButton = document.getElementById('copy-url') as HTMLButtonElement;
                    if (copyButton) {
                        delete copyButton.dataset.url;
                    }
                }

                // 更新请求列表
                this.tabRequests = result.requests.map((req: any) => new Request(req));

                // 排序请求（最新的在前面）
                this.tabRequests.sort((a, b) => {
                    return (b.createdAt?.getTime() || 0) - (a.createdAt?.getTime() || 0);
                });

                // 应用筛选
                this.filterRequests();
            } else {
                this.requestsEmptyState.textContent = result?.error || '无法加载请求';
            }
        } catch (error) {
            console.error('Error loading tab requests:', error);
            this.requestsEmptyState.textContent = '加载请求时发生错误';
        }
    }

    /**
     * 筛选请求
     */
    private filterRequests(): void {
        const filterText = this.filterRequestsInput.value.toLowerCase();
        const filterMethod = this.filterMethodSelect.value;
        const filterType = this.filterTypeSelect.value as RequestType;

        this.filteredRequests = this.tabRequests.filter(request => {
            // 筛选方法
            if (filterMethod && request.method !== filterMethod) {
                return false;
            }

            // 筛选类型
            if (filterType && filterType !== RequestType.ALL) {
                const requestType = this.getRequestType(request);
                if (requestType !== filterType) {
                    return false;
                }
            }

            // 筛选文本
            if (filterText) {
                return request.url.toLowerCase().includes(filterText);
            }

            return true;
        });

        this.updateRequestsList();
    }

    /**
     * 获取请求类型
     * @param request 请求对象
     * @returns 请求类型
     */
    private getRequestType(request: Request): RequestType {
        try {
            const url = new URL(request.url);
            const contentType = request.headers.find(h => 
                h.key.toLowerCase() === 'content-type' && h.enabled)?.value.toLowerCase() || '';
            const acceptHeader = request.headers.find(h => 
                h.key.toLowerCase() === 'accept' && h.enabled)?.value.toLowerCase() || '';
            const path = url.pathname.toLowerCase();
            
            // 判断是否是API请求（FETCH/XHR）
            // 1. 检查是否有XHR标记头
            const isXhr = request.headers.some(h => 
                h.key.toLowerCase() === 'x-requested-with' && 
                h.value.toLowerCase() === 'xmlhttprequest' && 
                h.enabled);
                
            // 2. 检查Content-Type或Accept头是否包含json或api相关值
            const apiContentTypes = ['application/json', 'application/xml', 'application/graphql'];
            const hasApiContentType = apiContentTypes.some(type => contentType.includes(type));
            const hasApiAcceptType = apiContentTypes.some(type => acceptHeader.includes(type));
            
            // 3. 检查URL路径是否包含API相关关键字
            const isApiPath = /\/(api|rest|graphql|v\d+|service)\//i.test(path);
            
            // 4. 如果URL中有.json或.xml等API响应格式后缀
            const hasApiExtension = path.endsWith('.json') || path.endsWith('.xml');
            
            if (isXhr || hasApiContentType || hasApiAcceptType || isApiPath || hasApiExtension) {
                return RequestType.FETCH_XHR;
            }
            
            // 以下是其他类型判断
            // 判断CSS请求
            if (path.endsWith('.css') || contentType.includes('text/css')) {
                return RequestType.CSS;
            }
            
            // 判断JS请求
            if (path.endsWith('.js') || 
                path.endsWith('.mjs') || 
                contentType.includes('javascript') || 
                contentType.includes('ecmascript')) {
                return RequestType.JS;
            }
            
            // 判断图片请求
            if (path.match(/\.(jpe?g|png|gif|svg|webp|ico|bmp)$/i) || 
                contentType.includes('image/')) {
                return RequestType.IMG;
            }
            
            return RequestType.OTHER;
        } catch {
            return RequestType.OTHER;
        }
    }

    /**
     * 更新请求列表UI
     */
    private updateRequestsList(): void {
        // 清空列表
        this.requestsList.innerHTML = '';

        if (this.filteredRequests.length === 0) {
            // 显示空状态
            this.requestsEmptyState.style.display = 'block';
            this.requestsEmptyState.textContent = this.tabRequests.length === 0 ?
                '当前页面没有捕获到请求' : '没有匹配的请求';
            return;
        }

        // 隐藏空状态
        this.requestsEmptyState.style.display = 'none';

        // 添加请求项
        this.filteredRequests.forEach(request => {
            const requestElement = this.createRequestItemElement(request);
            this.requestsList.appendChild(requestElement);
        });
    }

    /**
     * 创建请求项元素
     * @param request 请求对象
     * @returns 请求项元素
     */
    private createRequestItemElement(request: Request): HTMLDivElement {
        const element = document.createElement('div');
        element.className = 'request-item';

        // 添加方法
        const methodElement = document.createElement('div');
        methodElement.className = `request-method ${request.method.toLowerCase()}`;
        methodElement.textContent = request.method;
        element.appendChild(methodElement);

        // 添加URL
        const urlElement = document.createElement('div');
        urlElement.className = 'request-url';
        urlElement.textContent = this.getPathFromUrl(request.url);
        urlElement.title = request.url;
        element.appendChild(urlElement);

        // 添加状态（暂无）
        const statusElement = document.createElement('div');
        statusElement.className = 'request-status';
        element.appendChild(statusElement);

        // 添加类型
        const typeElement = document.createElement('div');
        typeElement.className = 'request-type';
        typeElement.textContent = this.getContentTypeLabel(request);
        element.appendChild(typeElement);

        // 添加时间
        const timeElement = document.createElement('div');
        timeElement.className = 'request-time';
        timeElement.textContent = request.createdAt ?
            formatDate(request.createdAt).split(' ')[1] : '';
        element.appendChild(timeElement);

        // 添加调试按钮
        const debugElement = document.createElement('div');
        debugElement.className = 'request-debug';
        const debugButton = document.createElement('button');
        debugButton.className = 'debug-button';
        debugButton.textContent = '调试';
        debugButton.addEventListener('click', (e) => {
            e.stopPropagation(); // 阻止冒泡避免触发行点击事件
            this.selectRequest(request);
        });
        debugElement.appendChild(debugButton);
        element.appendChild(debugElement);

        // 添加点击事件
        element.addEventListener('click', () => {
            // 高亮选中的请求
            const selectedElements = this.requestsList.querySelectorAll('.selected');
            selectedElements.forEach(el => el.classList.remove('selected'));
            element.classList.add('selected');
        });

        return element;
    }

    /**
     * 选择请求进行调试
     * @param request 选中的请求
     */
    private selectRequest(request: Request): void {
        if (this.onRequestSelect) {
            try {
                console.log('准备调试请求:', request);
                
                // 安全克隆请求对象
                // 避免JSON序列化问题，手动复制必要的属性
                const debugRequest = new Request({
                    id: crypto.randomUUID(),
                    name: request.name || '',
                    url: request.url || '',
                    method: request.method || 'GET', 
                    params: Array.isArray(request.params) ? 
                        request.params.map(p => ({...p})) : [],
                    headers: Array.isArray(request.headers) ? 
                        request.headers.map(h => ({...h})) : [],
                    bodyType: request.bodyType || 'none',
                    // 安全处理body属性，防止非法JSON值
                    body: this.safeCloneBody(request.body, request.bodyType),
                    createdAt: new Date()
                });
                
                console.log('创建的调试请求对象:', debugRequest);
                
                // 如果请求没有设置请求体类型，根据Content-Type设置
                if (debugRequest.bodyType === BodyType.NONE) {
                    const contentType = debugRequest.headers.find(h => 
                        h.key.toLowerCase() === 'content-type' && h.enabled)?.value.toLowerCase() || '';
                    
                    if (contentType.includes('application/json')) {
                        debugRequest.bodyType = BodyType.RAW;
                        // 如果没有请求体，但是内容类型是JSON，创建一个空的JSON对象
                        if (!debugRequest.body) {
                            debugRequest.body = '{}';
                        }
                    } else if (contentType.includes('application/x-www-form-urlencoded')) {
                        debugRequest.bodyType = BodyType.URLENCODED;
                        if (!Array.isArray(debugRequest.body)) {
                            debugRequest.body = [];
                        }
                    } else if (contentType.includes('multipart/form-data')) {
                        debugRequest.bodyType = BodyType.FORM_DATA;
                        if (!Array.isArray(debugRequest.body)) {
                            debugRequest.body = [];
                        }
                    }
                }
                
                // 调用回调函数，将请求传递给接口调试页面
                this.onRequestSelect(debugRequest);
            } catch (e) {
                // 使用具体类型处理错误
                const errorMessage = e instanceof Error ? e.message : String(e);
                console.error('处理调试请求时出错:', errorMessage);
                alert('调试请求失败: ' + errorMessage);
            }
        }
    }
    
    /**
     * 安全克隆请求体，处理可能的非法JSON值
     * @param body 原始请求体
     * @param bodyType 请求体类型
     * @returns 克隆的请求体
     */
    private safeCloneBody(body: any, bodyType: string): any {
        if (body === undefined || body === null) {
            // 根据请求体类型返回默认值
            switch (bodyType) {
                case BodyType.FORM_DATA:
                case BodyType.URLENCODED:
                    return [];
                case BodyType.RAW:
                    return '';
                default:
                    return undefined;
            }
        }
        
        // 根据类型处理
        if (body instanceof File) {
            // 文件对象无法克隆，返回null
            return null;
        } else if (Array.isArray(body)) {
            // 安全克隆数组
            return body.map(item => {
                if (typeof item === 'object' && item !== null) {
                    return {...item};
                }
                return item;
            });
        } else if (typeof body === 'object' && body !== null) {
            // 安全克隆对象
            return {...body};
        } else if (typeof body === 'string') {
            // 字符串直接返回
            return body;
        }
        
        // 其他类型转为字符串
        return String(body);
    }

    /**
     * 从URL中获取路径部分
     * @param url URL字符串
     * @returns 路径部分
     */
    private getPathFromUrl(url: string): string {
        try {
            const urlObj = new URL(url);
            return urlObj.pathname;
        } catch (error) {
            return url;
        }
    }

    /**
     * 获取请求的内容类型标签
     * @param request 请求对象
     * @returns 内容类型标签
     */
    private getContentTypeLabel(request: Request): string {
        const requestType = this.getRequestType(request);
        
        switch(requestType) {
            case RequestType.FETCH_XHR:
                return 'XHR/Fetch';
            case RequestType.CSS:
                return 'CSS';
            case RequestType.JS:
                return 'JS';
            case RequestType.IMG:
                return 'Image';
            case RequestType.OTHER:
            default:
                return this.getContentTypeFromUrl(request.url);
        }
    }

    /**
     * 从URL推断内容类型
     * @param url URL字符串
     * @returns 内容类型
     */
    private getContentTypeFromUrl(url: string): string {
        try {
            const urlObj = new URL(url);
            const path = urlObj.pathname;
            const extension = path.slice(path.lastIndexOf('.') + 1).toLowerCase();

            switch (extension) {
                case 'json':
                    return 'JSON';
                case 'xml':
                    return 'XML';
                case 'html':
                case 'htm':
                    return 'HTML';
                case 'js':
                    return 'JS';
                case 'css':
                    return 'CSS';
                case 'png':
                case 'jpg':
                case 'jpeg':
                case 'gif':
                case 'svg':
                case 'webp':
                    return 'Image';
                default:
                    return extension.toUpperCase() || 'Other';
            }
        } catch (error) {
            return 'Other';
        }
    }

    /**
     * 格式化URL用于显示
     * @param url URL对象
     * @returns 格式化后的URL字符串
     */
    private formatUrlForDisplay(url: URL): string {
        // 保留协议、主机名和截断的路径
        const host = url.hostname;
        const pathname = this.truncateText(url.pathname, 20);
        return `${host}${pathname}`;
    }
    
    /**
     * 截断文本
     * @param text 要截断的文本
     * @param maxLength 最大长度
     * @returns 截断后的文本
     */
    private truncateText(text: string, maxLength: number): string {
        if (text.length <= maxLength) {
            return text;
        }
        return text.substring(0, maxLength - 3) + '...';
    }

    /**
     * 复制URL到剪贴板
     */
    private async handleCopyUrl(event: MouseEvent): Promise<void> {
        const button = event.currentTarget as HTMLButtonElement;
        const url = button.dataset.url;
        
        if (!url) return;
        
        try {
            await navigator.clipboard.writeText(decodeURIComponent(url));
            
            // 显示复制成功提示
            const feedbackElement = document.getElementById('copy-feedback');
            if (feedbackElement) {
                feedbackElement.classList.add('show');
                
                // 2秒后隐藏提示
                setTimeout(() => {
                    feedbackElement.classList.remove('show');
                }, 2000);
            }
        } catch (err) {
            console.error('复制URL失败:', err);
        }
    }
} 